use crate::core::vec3::*;
use crate::core::ray::*;
use crate::core::material::*;
use std::rc::Rc;

pub struct HitRecord{
    pub p: Point3,
    // normal: Vec3New,
    pub normal: Option<Vec3New>,
    pub mat_ptr: Rc<dyn Material>,
    pub t: f64,
    // front_face: bool,
    pub front_face: Option<bool>,
}

impl HitRecord{
    pub fn set_face_front_and_noraml(&mut self, r:&Ray, outward_normal: &Vec3New){
        self.front_face = Some(dot(&r.direction(), outward_normal) < 0_f64);
        
        // 错误的法线设置
        // self.normal = if self.front_face.is_some() {
        //     Some(*outward_normal)
        // }else{
        //     Some(-*outward_normal)
        // };

        // 正确的法线设置
        self.normal = match self.front_face {
            Some(true) => Some(*outward_normal),
            _ => Some(-*outward_normal),
        }
    }
}

pub trait Hittable{
    // pub fn hit(&self, r: &Ray, t_min: f64, t_max: f64, rec: &hit_record) -> bool;
    fn hit(&self, r: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord>;
}

pub struct HittbaleList{
    pub objects:Vec<Box<dyn Hittable>>,
}

impl HittbaleList{
    pub fn new() -> Self{
        Self { objects: Vec::new() }
    }
    // pub fn from(object:Box<dyn Hittable>) -> Self{
    //     Self {
    //         objects:vec![object],
    //     }
    // }
    pub fn add(&mut self, object: Box<dyn Hittable>){
        self.objects.push(object);
    }
    // pub fn clear(&mut self){
    //     self.objects.clear();
    // }
}

impl Hittable for HittbaleList{
    fn hit(&self, r: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord>{
        let mut hit_record: Option<HitRecord> = None;
        let mut closest_so_far = t_max;

        for object in &self.objects{
            match object.hit(r, t_min, closest_so_far){
                Some(hit_rec)=>{
                    closest_so_far = hit_rec.t;
                    hit_record = Some(hit_rec);
                }
                None => {}
            }
        }
        hit_record
    }
}